"""
认证中间件
处理API Key认证和用户身份验证
"""
import time
from fastapi import Request, HTTPException, status
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware

from server.utils.auth_middleware import is_public_path, is_api_key_allowed_path, get_api_key_user, api_key_tracker
from src.utils.logging_config import logger


class AuthMiddleware(BaseHTTPMiddleware):
    """认证中间件，处理API Key和用户认证"""

    async def dispatch(self, request: Request, call_next):
        start_time = time.time()
        path = request.url.path

        # 添加调试日志
        logger.info(f"🔍 中间件处理请求: {path}")
        provided_api_key = request.headers.get("X-API-Key") or request.query_params.get("api_key")
        logger.info(f"🔍 提供的API Key: {'是' if provided_api_key else '否'}")

        # 检查是否为公开路径
        is_public = is_public_path(path)
        logger.info(f"🔍 是否为公开路径: {'是' if is_public else '否'}")

        # 处理API Key认证
        api_key_result = await self._handle_api_key_auth(request, path, provided_api_key, is_public)
        if api_key_result:
            return api_key_result

        # 如果API Key认证成功且已设置用户状态，直接处理请求
        if hasattr(request.state, 'is_api_key_user') and request.state.is_api_key_user:
            response = await call_next(request)
            self._track_api_key_usage(request, path, start_time, response)
            return response

        # 处理公开路径
        if is_public:
            response = await call_next(request)
            self._track_api_key_usage(request, path, start_time, response)
            return response

        # 处理非API路径
        if not path.startswith("/api"):
            return await call_next(request)

        # 处理Bearer token认证
        auth_result = await self._handle_bearer_auth(request, path)
        if auth_result:
            return auth_result

        # 继续处理请求
        response = await call_next(request)
        self._track_api_key_usage(request, path, start_time, response)
        return response

    async def _handle_api_key_auth(self, request: Request, path: str, provided_api_key: str, is_public: bool):
        """处理API Key认证"""
        if not provided_api_key:
            return None

        try:
            api_user = await get_api_key_user(request)
            if api_user:
                # API Key验证通过，继续处理
                request.state.user = api_user
                request.state.is_api_key_user = True

                # 检查路径权限
                if not is_api_key_allowed_path(path) and not is_public:
                    logger.warning(f"API Key用户无权访问路径: {path}")
                    return JSONResponse(
                        status_code=status.HTTP_403_FORBIDDEN,
                        content={
                            "detail": "API Key无权访问此接口",
                            "error_code": "INSUFFICIENT_PERMISSIONS",
                            "path": path
                        }
                    )
        except HTTPException as e:
            # API Key验证失败，直接返回错误
            return JSONResponse(
                status_code=e.status_code,
                content={
                    "detail": e.detail,
                    "error_code": "INVALID_API_KEY"
                },
                headers=getattr(e, 'headers', {})
            )

        return None

    async def _handle_bearer_auth(self, request: Request, path: str):
        """处理Bearer token认证"""
        auth_header = request.headers.get("Authorization")
        if auth_header and auth_header.startswith("Bearer "):
            # 提取并验证token
            token = auth_header.split("Bearer ")[1]
            request.state.token = token
            # 后续的用户认证在中间件之后的依赖项中处理
            return None
        else:
            # 既不是API Key也不是Bearer token，返回401
            return JSONResponse(
                status_code=status.HTTP_401_UNAUTHORIZED,
                content={
                    "detail": "请提供有效的认证信息（API Key或Bearer Token）",
                    "error_code": "MISSING_AUTHENTICATION",
                    "path": path,
                    "help": "在Header中添加 X-API-Key: your-api-key 或 Authorization: Bearer your-token"
                },
                headers={"WWW-Authenticate": "Bearer or X-API-Key"}
            )

    def _track_api_key_usage(self, request: Request, path: str, start_time: float, response):
        """跟踪API Key使用情况"""
        if hasattr(request.state, 'is_api_key_user') and request.state.is_api_key_user:
            duration = time.time() - start_time
            api_key_tracker.record_usage(
                client_ip=request.client.host,
                path=path,
                success=response.status_code < 400,
                duration=duration
            )